


abstract public class Simulation {
	//run simulation for time seconds. 
	//return the average throughput of the source
	
	protected double bTotal; //number of bits in the system buffers 
	protected  long tMax;   // bit/sec throughput of the sender
	protected ExpGenerator goodGenerator;
	protected ExpGenerator badGenerator;
	
	protected Node[] allNodes;
	
	public Simulation(double bTotal, long tMax, double lambda, double mu, int nodesNum) {
		this.bTotal = bTotal;
		this.tMax = tMax;
		allNodes = new Node[nodesNum];
		
		for(int i = 0; i < allNodes.length; ++i) {
			allNodes[i] = new Node();
			allNodes[i].reset();
			allNodes[i].id = i;
			//check
			//allNodes[i].relIdx = bTotal;
		}
		
		goodGenerator = new ExpGenerator(lambda);
		badGenerator = new ExpGenerator(mu);
	}
	
	abstract public  double makeNodesShift(double maxDistanceToRun);
	abstract protected void removeFromBadList(Node node);
	abstract protected void addToBadList(Node node);
	
	public double run(double timeWarm, double timeSample) {
		double srcSteps = 0;	
		double elapsedTime = 0;
		double time = timeWarm + timeSample;
		
		EventsContainer evCont  = new EventsContainer(allNodes, goodGenerator, badGenerator); 
	
		while(elapsedTime < time) {
			Event ev = evCont.pollEvent();
			double relDuration = ev.getRelDuration();
			if(time - elapsedTime < relDuration) relDuration = time - elapsedTime;
			
			double maxDistanceToRun = relDuration * (double)tMax;
			
			elapsedTime += relDuration;
			
			if(elapsedTime < timeWarm)
				makeNodesShift(maxDistanceToRun);
			else
				srcSteps += makeNodesShift(maxDistanceToRun);		
			
			//update the node's state by event
			Node evNode= ev.getNode();
			evNode.state = ev.getState();
			
			if(ev.getState()== State.Good) { 
				removeFromBadList(evNode);
			} else {
				addToBadList(evNode);
			}

		}
		return srcSteps;
	}
	
	public void printNodes() {
		for(int i = 0; i < allNodes.length; ++i) {
			System.out.print("ID: " + i + ", relIdx: " + allNodes[i].relIdx + ", State: " + allNodes[i].state + " ");
		}
		System.out.print("\n\n");
	}

}
